﻿#include "ndc_client.h"
#include <QDebug>

NDC_Client::NDC_Client(QObject *parent) : QObject(parent)
{

}

void NDC_Client::setModbusPtr(modbus* modbus){

    //modbus_ = modbus;
}

bool NDC_Client::read_AGV_State(){

    /*
    if(modbus_ == nullptr){
        return false;
    }

    uint16_t read_holding_regs[6];
    int state = modbus_->modbus_read_holding_registers(52,6,read_holding_regs);

    //qDebug() << "state" << state;

    if(state == 0){

        station_number = read_holding_regs[0];
        allow_put_raw_workpiece_to_CNC = read_holding_regs[1]; // 以AGV为基准，下料
        allow_take_workpiece_from_CNC = read_holding_regs[2];  // 以AGV为基准，上料
        allow_take_raw_workpiece_from_lifter = read_holding_regs[3];
        allow_put_workpiece_to_lifter = read_holding_regs[4];
        AGV_State = read_holding_regs[5];

        qDebug() << "---------------------------------------";
        qDebug() << "read_holding_regs "
                 << read_holding_regs[0] << " "
                 << read_holding_regs[1] << " "
                 << read_holding_regs[2] << " "
                 << read_holding_regs[3] << " "
                 << read_holding_regs[4] << " "
                 << read_holding_regs[5];

            return true;
    }
    else{
        qDebug() << "NG";
            return false;
    }
    */

    //////////////////////////////////////////////////////////////

    if (!modbusDevice)
        return false;
    //ui->readValue->clear();
    //statusBar()->clearMessage();

    if (auto *reply = modbusDevice->sendReadRequest(readRequest(), 1)) {

        reply_state = false;

        if (!reply->isFinished()){
            connect(reply, &QModbusReply::finished, this, &NDC_Client::readReady);
        }else{
            qDebug() << "broadcast replies return immediately";
            //delete reply; // broadcast replies return immediately
            readReady();
        }

    } else {
        //statusBar()->showMessage(tr("Read error: ") + modbusDevice->errorString(), 5000);
        qDebug() << "Read error: " << modbusDevice->errorString();
    }

    sleep_ms(500);

    if(reply_state == true){
        //qDebug() << "read modbus success";
        return true;
    }
    else{
        qDebug() << "read modbus fail";
        return false;
    }


}


//uint16_t *NDC_Client::read_product_qrlandmark_data()
//{
//    modbus_->modbus_read_holding_registers(75,17,read_holding_regs_product_qrlandark);
//    return read_holding_regs_product_qrlandark;
//}


bool NDC_Client::write_ADV_data_64(int data64)
{
    /*
    if(modbus_ == nullptr) return false;

    uint16_t write_holding_regs[1];
    write_holding_regs[0] = data64;
    int state = modbus_->modbus_write_registers(64,1,write_holding_regs);

    if(state == 0){
        return true;
    }else{
        return false;
    }
    */


    ////////////////////////////////////////////////////////////////////
    int data[1] = {data64};
    bool w_state = write_data(64,1,data);
    return w_state;

}

bool NDC_Client::write_ADV_data_65(int data65)
{
    /*
        if(modbus_ == nullptr) return false;

    uint16_t write_holding_regs[1];
    write_holding_regs[0] = data65;
    int state = modbus_->modbus_write_registers(65,1,write_holding_regs);
    qDebug() << "read_holding_regs " << write_holding_regs[0];

    if(state == 0){
        return true;
    }else{
        return false;
    }
    */

    ////////////////////////////////////////////////////////////////////

    int data[1] = {data65};
    bool w_state = write_data(65,1,data);
    return w_state;
}

bool NDC_Client::write_ADV_data_66(int data66)
{
    /*
        if(modbus_ == nullptr) return false;

    uint16_t write_holding_regs[2];
    write_holding_regs[0] = data66;
    write_holding_regs[1] = data66;
    int state = modbus_->modbus_write_registers(66,2,write_holding_regs);

    if(state == 0){
        return true;
    }else{
          return false;
    }
    */


    ////////////////////////////////////////////////////////////////////

    int data[1] = {data66};
    bool w_state = write_data(66,1,data);
    return w_state;
}

/*
bool NDC_Client::write_AGV_data(int index, int data){

        if(modbus_ == nullptr) return false;

    uint16_t write_holding_regs[1];
    write_holding_regs[0] = data;
    int state = modbus_->modbus_write_registers(index,1,write_holding_regs);

    if(state == 0){
        return true;
    }else{
        return false;
    }
}
*/

bool NDC_Client::write_ADV_data_67(int data67)
{
    /*
        if(modbus_ == nullptr) return false;

    uint16_t write_holding_regs[1];
    write_holding_regs[0] = data67;
    int state = modbus_->modbus_write_registers(67,1,write_holding_regs);

    if(state == 0){
        return true;
    }else{
        return false;
    }
    */

    ////////////////////////////////////////////////////////////////////

    int data[1] = {data67};
    bool w_state = write_data(67,1,data);
    return w_state;
}


bool NDC_Client::write_AGV_data_68(int data68){

    /*
        if(modbus_ == nullptr) return false;

    uint16_t write_holding_regs[1];
    write_holding_regs[0] = data68;
    int state = modbus_->modbus_write_registers(68,1,write_holding_regs);

    if(state == 0){
        return true;
    }else{
        return false;
    }
    */

    ////////////////////////////////////////////////////////////////////

    int data[1] = {data68};
    bool w_state = write_data(68,1,data);
    return w_state;
}

bool NDC_Client::write_AGV_data_69(int data69){

    /*
    if(modbus_ == nullptr) return false;

    uint16_t write_holding_regs[1];
    write_holding_regs[0] = data69;
    int state = modbus_->modbus_write_registers(69,1,write_holding_regs);

    if(state == 0){
        return true;
    }else{
        return false;
    }
    */

    ////////////////////////////////////////////////////////////////////

    int data[1] = {data69};
    bool w_state = write_data(69,1,data);
    return w_state;
}

bool NDC_Client::Func_allow_take_workpiece_from_CNC(int& value){

    if(reply_state == false ) return false;

    value = allow_take_workpiece_from_CNC;

    return true;

}

bool NDC_Client::Func_allow_put_raw_workpiece_to_CNC(int& value){

    if(reply_state == false ) return false;

    value = allow_put_raw_workpiece_to_CNC;
    return true;
}

bool NDC_Client::Func_allow_take_raw_workpiece_from_lifter(int& value){

    if(reply_state == false ) return false;

    value = allow_take_raw_workpiece_from_lifter;

    return true;
}

bool NDC_Client::Func_allow_put_workpiece_to_lifter(int& value){

    if(reply_state == false ) return false;

    value = allow_put_workpiece_to_lifter;

    return true;
}

bool NDC_Client::Func_finished_putting_raw_workpiece_to_CNC(int& value){

    if(reply_state == false ) return false;

    value = finished_putting_raw_workpiece_to_CNC;
    return true;
}

bool NDC_Client::Func_finished_taking_workpiece_from_CNC(int& value){

    if(reply_state == false ) return false;

    value = finished_taking_workpiece_from_CNC;
    return true;

}

bool NDC_Client::Func_allow_lifter_movement(int& value){

    if(reply_state == false ) return false;

    value = allow_lifter_movement;
    return true;

}

bool NDC_Client::Func_AGV_arrive_station_number(int& number){

    if(reply_state == false ) return false;

    number = station_number;
    return true;
}

bool NDC_Client::Func_get_station_id(QString& value){

    if(reply_state == false ) return false;

    value = QString::number(station_number);

    return true;
}

bool NDC_Client::Func_get_AGV_state(int& value){

    if(reply_state == false ) return false;

    value = AGV_State;

    return true;
}


bool NDC_Client::write_DM_code_to_NDC(std::string message){

    int w_state = -1;

    if(message.empty()){
        //w_state = modbus_->modbus_write_register(76,2);
        int data[1] = {2};
        w_state = write_data(76,1,data);
    }
    else
    {
        //w_state = modbus_->modbus_write_register(76,1);
        //
        //解码，message转换成十进制或十六进制，输入到列表

        int write_holding_regs[17];

        write_holding_regs[0] = 1;

        for(int i=1; i<17; i++){
            write_holding_regs[i] = message.at(i-1);
            //qDebug() << " " << message.at(i-1) << " -> "
            //         << write_holding_regs[i];
        }

        //EDG0000012422086
        //w_state = modbus_->modbus_write_registers(76,17,write_holding_regs);
        w_state = write_data(76,17,write_holding_regs);
    }

    if(w_state == 0){
        return true;
    }else{
        return false;
    }
}

bool NDC_Client::connectToHost(std::string host, int port){

    /*
    m_host = host;
    m_port = port;

    if(modbus_ == nullptr){
        modbus_ = new modbus(host , port);
    }

    modbus_->modbus_set_slave_id(1);

    bool state = modbus_->modbus_connect();

    if(state == true){
        qDebug() << "modbus_tcp_ connect success!";
        return true;
    }
    else{
        qDebug() << "modbus_tcp_ connect fail!";
        return false;
    }
    */

    //

    /////////////////////////////////////////////////////////////////

    if (modbusDevice != nullptr)
        return true;

    modbusDevice = new QModbusTcpClient(this);

    //statusBar()->clearMessage();
    if (modbusDevice->state() != QModbusDevice::ConnectedState) {

        //const QUrl url = QUrl::fromUserInput(ui->portEdit->text());
        modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);
        modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, QString::fromStdString(host));

        modbusDevice->setTimeout(1000);
        modbusDevice->setNumberOfRetries(3);
        if (!modbusDevice->connectDevice()) {
            //statusBar()->showMessage(tr("Connect failed: ") + modbusDevice->errorString(), 5000);
            //qDebug() << "modbusDevice connectDevice fail";
            return false;
        } else {
            //qDebug() << "modbusDevice connectDevice success";
            //ui->actionConnect->setEnabled(false);
            //ui->actionDisconnect->setEnabled(true);
            return true;
        }
    }

    return true;
}

bool NDC_Client::disconnect(){

    /*
    if(modbus_ != nullptr){
        modbus_->modbus_close();

        delete modbus_;
    }

    return true;
    */

    if(modbusDevice == nullptr){
        return true;
    }
    else{
        modbusDevice->disconnectDevice();
    }

    return true;

}

bool NDC_Client::check_Modbus_Available(){

    /*
    if(modbus_ == nullptr){
        return false;
    }
    else{
       if(modbus_->is_connected()){
            return true;
       }
       else{
           connectToHost(m_host,m_port);
           qDebug() << "try reconnonect modbus";
       }

    }
    */


    if (modbusDevice->state() != QModbusDevice::ConnectedState){
        bool state = modbusDevice->connectDevice();
        return state;
    }
    else{
        return true;
    }



}

NDC_Client::~NDC_Client(){
    disconnect();
}


QModbusDataUnit NDC_Client::readRequest() const
{
    const auto table =
            static_cast<QModbusDataUnit::RegisterType> (4);

    int startAddress = 52;
    //Q_ASSERT(startAddress >= 0 && startAddress < 10);

    // do not go beyond 10 entries
    int numberOfEntries = 6;//qMin(ui->readSize->currentText().toInt(), 10 - startAddress);
    return QModbusDataUnit(table, startAddress, numberOfEntries);
}

QModbusDataUnit NDC_Client::writeRequest(int start,int number) const
{
    const auto table =
            static_cast<QModbusDataUnit::RegisterType> (4);

    int startAddress = start;
    //Q_ASSERT(startAddress >= 0 && startAddress < 10);

    // do not go beyond 10 entries
    int numberOfEntries = number;//qMin(ui->writeSize->currentText().toInt(), 10 - startAddress);
    return QModbusDataUnit(table, startAddress, numberOfEntries);
}

void NDC_Client::readReady()
{
    auto reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
        return;

    if (reply->error() == QModbusDevice::NoError) {
        const QModbusDataUnit unit = reply->result();

        int reply_data[6];

        for (uint i = 0; i < unit.valueCount(); i++) {
            const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress())
                    .arg(QString::number(unit.value(i),
                                         unit.registerType() <= QModbusDataUnit::Coils ? 10 : 16));
            //qDebug() << "entry " << entry;
            //ui->readValue->addItem(entry);
            reply_data[i] = unit.value(i);
        }

        station_number = reply_data[0];
        allow_put_raw_workpiece_to_CNC = reply_data[1]; // 以AGV为基准，下料
        allow_take_workpiece_from_CNC = reply_data[2];  // 以AGV为基准，上料
        allow_take_raw_workpiece_from_lifter = reply_data[3];
        allow_put_workpiece_to_lifter = reply_data[4];
        AGV_State = reply_data[5];

//        qDebug() << "reply_data "
//                 << reply_data[0] << " "
//                 << reply_data[1] << " "
//                 << reply_data[2] << " "
//                 << reply_data[3] << " "
//                 << reply_data[4] << " "
//                 << reply_data[5];

        reply_state = true;


    } else if (reply->error() == QModbusDevice::ProtocolError) {
        //statusBar()->showMessage(tr("Read response error: %1 (Mobus exception: 0x%2)").
        //                           arg(reply->errorString()).
        //                            arg(reply->rawResult().exceptionCode(), -1, 16), 5000);
    } else {
        //statusBar()->showMessage(tr("Read response error: %1 (code: 0x%2)").
        //                            arg(reply->errorString()).
        //                            arg(reply->error(), -1, 16), 5000);
    }

    reply->deleteLater();
}


bool NDC_Client::write_data(int start,int number,int* data){

    if (!modbusDevice)
        return false;

    QModbusDataUnit writeUnit = writeRequest(start,number);
    QModbusDataUnit::RegisterType table = writeUnit.registerType();
    for (uint i = 0; i < writeUnit.valueCount(); i++) {
        writeUnit.setValue(i, data[i]);
    }

    if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, 1)) {
        if (!reply->isFinished()) {
            connect(reply, &QModbusReply::finished, this, [this, reply]() {
                if (reply->error() == QModbusDevice::ProtocolError) {
                    //statusBar()->showMessage(tr("Write response error: %1 (Mobus exception: 0x%2)")
                    //    .arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16),
                    //    5000);
                } else if (reply->error() != QModbusDevice::NoError) {
                    //statusBar()->showMessage(tr("Write response error: %1 (code: 0x%2)").
                    //    arg(reply->errorString()).arg(reply->error(), -1, 16), 5000);

                }

                //qDebug() << "modbus write success";
                reply->deleteLater();
            });
        } else {
            // broadcast replies return immediately
            reply->deleteLater();
        }
    } else {
        //statusBar()->showMessage(tr("Write error: ") + modbusDevice->errorString(), 5000);
    }
}

void NDC_Client::sleep_ms(int msecond){
    QTime dieTime = QTime::currentTime().addMSecs(msecond);
    while( QTime::currentTime() < dieTime ){
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
    }
}
